/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package maquinavirtual;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author David
 */
public class MaquinaVirtual {

    /**
     * @param args the command line arguments
     */
    
    private int _contadorPrograma;
 //   private int _cimaPila;
    private boolean _regParada;
    private Stack _pila;
    private ArrayList _memoriaDatos;
    private ArrayList<String> _memoriaInstrucciones;
    private FileReader fr;
    private BufferedReader br;
   // private Class class
    
    //True=1 , False=0{}
    public MaquinaVirtual()
    {
        try {
            this.fr = new FileReader("archivo.obj");
            this.br = new BufferedReader(this.fr);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(MaquinaVirtual.class.getName()).log(Level.SEVERE, null, ex);
        }
        String inst;
        try {
            while ((inst = br.readLine()) != null)
            {
                _memoriaInstrucciones.add(inst);
            }
        } catch (IOException ex) {
            Logger.getLogger(MaquinaVirtual.class.getName()).log(Level.SEVERE, null, ex);
        }

        
    }
    
    public void cargaMemInstrucciones(ArrayList<String> mIns)
    {
        _memoriaInstrucciones=mIns;
    }
    
    public void ejecutaMaquina()
    {
        _contadorPrograma=this._memoriaInstrucciones.size()-1;
        //_cimaPila=0;
        _regParada=true;
        String instruccion;
        while(!(instruccion=_memoriaInstrucciones.get(_contadorPrograma)).equals("Stop"))
        {
            
        }
    }
    
    private void apila(Object num)
    {
        this._pila.push(num);
        this._contadorPrograma++;
    }
    
    private void apilaDir(int direccion)
    {
        if(direccion>=0 && this._memoriaDatos.get(direccion)!=null ){
            _pila.push(this._memoriaDatos.get(direccion));
            this._contadorPrograma++;
        }
    }
    
    private void desapilaDir(int direccion)
    {
       if(direccion>=0 && !this._pila.empty())
           if(this._memoriaDatos.size()< direccion)
               for(int i=this._memoriaDatos.size();i<direccion+1;i++)
                   this._memoriaDatos.add(null);
           this._memoriaDatos.add(this._pila.pop());
           this._contadorPrograma++;
    }
    
    private void suma()
    {
        if (this._pila.size() >= 2)
        {
            Object op1 =  this._pila.peek();
            this._pila.pop();
            Object op0 = this._pila.peek();  
            this._pila.pop();
            if((op1 instanceof Float) ||(op0 instanceof Float))
            {
                op1 = (Float)op0 + (Float)op1;
                this._pila.push(op1);
            }else {
                op1 = (Integer)op0 + (Integer)op1;
                this._pila.push(op1);
            }
                this._contadorPrograma++;  
            
        } 
    }
    
    private void resta()
    {
        if (this._pila.size() >= 2)
        {
            Object op1 =  this._pila.peek();
            this._pila.pop();
            Object op0 = this._pila.peek();  
            this._pila.pop();
            if((op1 instanceof Float) ||(op0 instanceof Float))
            {
                op1 = (Float)op0 - (Float)op1;
                this._pila.push(op1);
            }else {
                op1 = (Integer)op0 - (Integer)op1;
                this._pila.push(op1);
            }
            this._contadorPrograma++;
        } 
    }
    
    private void multiplicacion()
    {
        if (this._pila.size() >= 2)
        {
            Object op1 =  this._pila.peek();
            this._pila.pop();
            Object op0 = this._pila.peek();  
            this._pila.pop();
            if((op1 instanceof Float) ||(op0 instanceof Float))
            {
                op1 = (Float)op0 * (Float)op1;
                this._pila.push(op1);
            }else {
                op1 = (Integer)op0 * (Integer)op1;
                this._pila.push(op1);
            }
            this._contadorPrograma++;
        } 
    }
   
    private void division()
    {
        if (this._pila.size() >= 2)
        {
            Object op1 =  this._pila.peek();
            this._pila.pop();
            Object op0 = this._pila.peek();  
            this._pila.pop();
            if((op1 instanceof Float) ||(op0 instanceof Float))
            {
                op1 = (Float)op0 / (Float)op1;
                this._pila.push(op1);
            }else {
                op1 = (Integer)op0 / (Integer)op1;
                this._pila.push(op1);
            }
            this._contadorPrograma++; 
            }else
            {
               /// Division por cero mostrar error; 
            }
        } 
    
    
    private void modulo()
    {
        if (this._pila.size() >= 2)
        {
            Object op1 =  this._pila.peek();
            this._pila.pop();
            Object op0 = this._pila.peek();  
            this._pila.pop();
            if ( (op1 instanceof Integer) &&(op0 instanceof Integer)&&((Integer)op1 != 0) )
                {
                op1 = (Integer) op0 % (Integer)op1; /// Division por cero mostrar error;
                this._pila.push(op1);
                this._contadorPrograma++; 
            }else
            {
               /// Division por cero mostrar error; 
            }
            
            
            
        } 
    }
    
    private void and()
    {
        if (this._pila.size() >= 2)
        {
            Object op1 =  this._pila.peek();
            this._pila.pop();
            Object op0 = this._pila.peek();  
            this._pila.pop();
            if((op1 instanceof Boolean) && (op0 instanceof Boolean))
            {
                op1 = (Boolean)op0 && (Boolean)op1;
                this._pila.push(op1);
                this._contadorPrograma++;
            
            }else
            {
                //Error en ejecucion
            } 
               
        } 
    }
    
    private void or()
    {
        if (this._pila.size() >= 2)
        {
            Object op1 =  this._pila.peek();
            this._pila.pop();
            Object op0 = this._pila.peek();  
            this._pila.pop();
            if((op1 instanceof Boolean) && (op0 instanceof Boolean))
            {
                op1 = (Boolean)op0 || (Boolean)op1;
                this._pila.push(op1);
                this._contadorPrograma++;
            
            }else
            {
                //Error en ejecucion
            } 
        } 
    }
    
    private void not()
    {
        if (this._pila.size() >= 1)
        {
            Object op1 =  this._pila.peek();
            this._pila.pop();            
            if((op1 instanceof Boolean))
            {
                op1 = !(Boolean)op1;
                this._pila.push(op1);
                this._contadorPrograma++;
            
            }else
            {
                //Error en ejecucion
            } 
            
            
        } 
    }
    
    private void inversa()
    {
        if (this._pila.size() >= 1)
        {
            Object op1 = this._pila.peek();
            this._pila.pop();
            if((op1 instanceof Float))
            {
                op1 = -(Float)op1;
                this._pila.push(op1);
            }else {
                op1 = -(Integer)op1;
                this._pila.push(op1);
            }
            this._contadorPrograma++;
            
        } 
    }
    
    private void menor()
    {
        if (this._pila.size() >= 2)
        {
            Object op1 =  this._pila.peek();
            this._pila.pop();
            Object op0 = this._pila.peek();  
            this._pila.pop();
            if((op1 instanceof Float) ||(op0 instanceof Float))
            {
                boolean b = (Float)op0 < (Float)op1;
                this._pila.push(b);
            }else 
                if((op1 instanceof Integer) ||(op0 instanceof Integer)){
                    boolean b = (Integer)op0 < (Integer)op1;
                    this._pila.push(b);
                }else
                    if((op1 instanceof Character) ||(op0 instanceof Character))
                    {
                        boolean b = (Character)op0 < (Character)op1;
                        this._pila.push(b);
                    }else
                        if((Boolean)op0==true) {
                            boolean b = true;
                            this._pila.push(b);   
                        }
            this._contadorPrograma++;
        } 
    }
    
    private void mayor()
    {
        Object op1 =  this._pila.peek();
            this._pila.pop();
            Object op0 = this._pila.peek();  
            this._pila.pop();
            if((op1 instanceof Float) ||(op0 instanceof Float))
            {
                boolean b = (Float)op0 > (Float)op1;
                this._pila.push(b);
            }else 
                if((op1 instanceof Integer) ||(op0 instanceof Integer)){
                    boolean b = (Integer)op0 > (Integer)op1;
                    this._pila.push(b);
                }else
                    if((op1 instanceof Character) ||(op0 instanceof Character))
                    {
                        boolean b = (Character)op0 > (Character)op1;
                        this._pila.push(b);
                    }else
                        if((Boolean)op1==true) {
                            boolean b = false;
                            this._pila.push(b);   
                        }
            this._contadorPrograma++;
    }
    
    private void mayorOigual()
    {
        if (this._pila.size() >= 2)
        {
            Object op1 =  this._pila.peek();
            this._pila.pop();
            Object op0 = this._pila.peek();  
            this._pila.pop();
            if((op1 instanceof Float) ||(op0 instanceof Float))
            {
                boolean b = (Float)op0 >= (Float)op1;
                this._pila.push(b);
            }else 
                if((op1 instanceof Integer) ||(op0 instanceof Integer)){
                    boolean b = (Integer)op0 >= (Integer)op1;
                    this._pila.push(b);
                }else
                    if((op1 instanceof Character) ||(op0 instanceof Character))
                    {
                        boolean b = (Character)op0 >= (Character)op1;
                        this._pila.push(b);
                    }else
                        if((Boolean)op1==true) {
                            boolean b = false;
                            this._pila.push(b);   
                        }
            this._contadorPrograma++;
        } 
    }//
    
    private void menorOigual()
    {
        if (this._pila.size() >= 2)
        {
            int op1 = this._pila.peek();
            this._pila.pop();
            int op0 = this._pila.peek();  
            this._pila.pop();
            if (op0 <= op1)
                this._pila.push(1); 
            else
                this._pila.push(0);
            this._contadorPrograma++; 
        } 
    }
    
    private void igual()
    {
        if (this._pila.size() >= 2)
        {
            int op1 = this._pila.peek();
            this._pila.pop();
            int op0 = this._pila.peek();  
            this._pila.pop();
            if (op0 == op1)
                this._pila.push(1); 
            else
                this._pila.push(0);
            this._contadorPrograma++; 
        } 
    }
    private void distinto()
    {
        if (this._pila.size() >= 2)
        {
            int op1 = this._pila.peek();
            this._pila.pop();
            int op0 = this._pila.peek();  
            this._pila.pop();
            if (op0 != op1)
                this._pila.push(1); 
            else
                this._pila.push(0);
            this._contadorPrograma++; 
        } 
    }
    
    private void desplazaIzq()
    {
        if (this._pila.size() >= 2)
        {
            int op1 = this._pila.peek();
            this._pila.pop();
            int op0 = this._pila.peek();  
            this._pila.pop();
            for(int i=0;i<op1;i++)
                op0=op0*2;
                this._pila.push(op0); 
            this._contadorPrograma++; 
        } 
    }
    
    private void desplazaDer()
    {
        if (this._pila.size() >= 2)
        {
            int op1 = this._pila.peek();
            this._pila.pop();
            int op0 = this._pila.peek();  
            this._pila.pop();
            for(int i=0;i<op1;i++)
                op0=op0/2;
                this._pila.push(op0); 
            this._contadorPrograma++; 
        } 
    }
    
    public static void main(String[] args) {
        // TODO code application logic here
    }

}
